4a51b5c849ceec88ef7103940df291a2b8cdf652,src/org/exist/xquery/GeneralComparison.java,GeneralComparison,quickNodeSetCompare,#Sequence#,453

Before Change


			context.getProfiler().message(this, Profiler.OPTIMIZATION_FLAGS, "OPTIMIZATION CHOICE", "quickNodeSetCompare");

		// if the context sequence hasn't changed we can return a cached result
		if(cached != null && cached.isValid(contextSequence)) {
			LOG.debug("Using cached results");
            if(context.getProfiler().isEnabled())
                context.getProfiler().message(this, Profiler.OPTIMIZATIONS, "OPTIMIZATION", "Returned cached result");
			return(cached.getResult());
		}

		//get the NodeSet on the left
		NodeSet nodes = (NodeSet) getLeft().eval(contextSequence);
		if(!(nodes instanceof VirtualNodeSet) && nodes.isEmpty()) //nothing on the left, so nothing to do
            return(Sequence.EMPTY_SEQUENCE);

        //get the Sequence on the right
		Sequence rightSeq = getRight().eval(contextSequence);
		if(rightSeq.isEmpty())	//nothing on the right, so nothing to do
            return(Sequence.EMPTY_SEQUENCE);

		//Holds the result
		NodeSet result = null;

		//get the type of a possible index
		int indexType = nodes.getIndexType();
        
        //See if we have a range index defined on the nodes in this sequence
        //TODO : use isSubType ??? -pb
		//rememeber that Type.ITEM means... no index ;-)
	    if(indexType != Type.ITEM) {
	    	if (LOG.isTraceEnabled())
	    		LOG.trace("found an index of type: " + Type.getTypeName(indexType));

	    	//Get the documents from the node set
			DocumentSet docs = nodes.getDocumentSet();

			//Iterate through the right hand sequence
			for (SequenceIterator itRightSeq = rightSeq.iterate(); itRightSeq.hasNext();) {
				//Get the index key
				Item key = itRightSeq.nextItem().atomize();

				//if key has truncation, convert it to string
		        if(truncation != Constants.TRUNC_NONE) {
		        	//TODO : log this conversion ? -pb
		        	//truncation is only possible on strings
		        	key = key.convertTo(Type.STRING);
		        }
		        //else if key is not the same type as the index
                //TODO : use isSubType ??? -pb
		        else if (key.getType() != indexType) {
		        	//try and convert the key to the index type
	            	try	{
	            		key = key.convertTo(indexType);
					} catch(XPathException xpe)	{
	            		//TODO : rethrow the exception ? -pb

			        	//Could not convert the key to a suitable type for the index, fallback to nodeSetCompare()
		                if(context.getProfiler().isEnabled())
		                    context.getProfiler().message(this, Profiler.OPTIMIZATION_FLAGS, "OPTIMIZATION FALLBACK", "Falling back to nodeSetCompare (" + xpe.getMessage() + ")");

		                if (LOG.isTraceEnabled())
		                	LOG.trace("Cannot convert key: " + Type.getTypeName(key.getType()) + " to required index type: " + Type.getTypeName(indexType));

			            return nodeSetCompare(nodes, contextSequence);
					}
		        }

		        // If key implements org.exist.storage.Indexable, we can use the index
		        if (key instanceof Indexable) {
		        	if (LOG.isTraceEnabled())
		        		LOG.trace("Checking if range index can be used for key: " + key.getStringValue());

		        	if (Type.subTypeOf(key.getType(), indexType)) {
			        	if(truncation == Constants.TRUNC_NONE) {
			        		if (LOG.isTraceEnabled())
			        			LOG.trace("Using range index for key: " + key.getStringValue());

			        		//key without truncation, find key
		                    context.getProfiler().message(this, Profiler.OPTIMIZATIONS, "OPTIMIZATION", "Using value index '" + context.getBroker().getValueIndex().toString() +
		                    		"' to find key '" + Type.getTypeName(key.getType()) + "(" + key.getStringValue() + ")'");

                            if (!checkForQNameIndex(contextSequence)) {
                                LOG.trace("Cannot use QName index");
                                contextQName = null;
                            }
                            
                            NodeSet ns = context.getBroker().getValueIndex().find(relation, docs, nodes, NodeSet.ANCESTOR, contextQName, (Indexable)key);
		                    hasUsedIndex = true;

		                    if (result == null)
								result = ns;
							else
								result = result.union(ns);

		                } else {
				        	//key with truncation, match key
                            if (LOG.isTraceEnabled())
                                context.getProfiler().message(this, Profiler.OPTIMIZATIONS, "OPTIMIZATION", "Using value index '" + context.getBroker().getValueIndex().toString() +
		                    		"' to match key '" + Type.getTypeName(key.getType()) + "(" + key.getStringValue() + ")'");

                            if (LOG.isTraceEnabled())
			        			LOG.trace("Using range index for key: " + key.getStringValue());

                            try {
								NodeSet ns = context.getBroker().getValueIndex().match(docs, nodes, NodeSet.ANCESTOR,
                                        getRegexp(key.getStringValue()).toString(), null, DBBroker.MATCH_REGEXP);
								hasUsedIndex = true;

								if (result == null)
									result = ns;
								else
									result = result.union(ns);

							} catch (EXistException e) {
								throw new XPathException(getASTNode(), e.getMessage(), e);
							}
						}
			        } else {
			        	//the datatype of our key does not
			        	//implement org.exist.storage.Indexable or is not of the correct type
		                if(context.getProfiler().isEnabled())
		                    context.getProfiler().message(this, Profiler.OPTIMIZATION_FLAGS, "OPTIMIZATION FALLBACK", "Falling back to nodeSetCompare (key is of type: " +
		                    		Type.getTypeName(key.getType()) + ") whereas index is of type '" + Type.getTypeName(indexType) + "'");

		                if (LOG.isTraceEnabled())
		                	LOG.trace("Cannot use range index: key is of type: " + Type.getTypeName(key.getType()) + ") whereas index is of type '" +
		                			Type.getTypeName(indexType));

		                return(nodeSetCompare(nodes, contextSequence));
			        }
		        } else {
		        	//the datatype of our key does not implement org.exist.storage.Indexable

After Change


		if(rightSeq.isEmpty()) {
			//Well, we might discuss this one ;-)
			hasUsedIndex= true;
            return Sequence.EMPTY_SEQUENCE;
		}
		
		//get the type of a possible index
		int indexType = nodes.getIndexType();
        
        //See if we have a range index defined on the nodes in this sequence
        //TODO : use isSubType ??? -pb
		//rememeber that Type.ITEM means... no index ;-)
	    if(indexType != Type.ITEM) {
	    	if (LOG.isTraceEnabled())
	    		LOG.trace("found an index of type: " + Type.getTypeName(indexType));

	    	//Get the documents from the node set
			DocumentSet docs = nodes.getDocumentSet();
			
	        //Holds the result
    		NodeSet result = null;

			//Iterate through the right hand sequence
			for (SequenceIterator itRightSeq = rightSeq.iterate(); itRightSeq.hasNext();) {
				//Get the index key
				Item key = itRightSeq.nextItem().atomize();

				//if key has truncation, convert it to string
		        if(truncation != Constants.TRUNC_NONE) {
		        	//TODO : log this conversion ? -pb
		        	//truncation is only possible on strings
		        	key = key.convertTo(Type.STRING);
		        }
		        //else if key is not the same type as the index
                //TODO : use isSubType ??? -pb
		        else if (key.getType() != indexType) {
		        	//try and convert the key to the index type
	            	try	{
	            		key = key.convertTo(indexType);
					} catch(XPathException xpe)	{
	            		//TODO : rethrow the exception ? -pb

			        	//Could not convert the key to a suitable type for the index, fallback to nodeSetCompare()
		                if(context.getProfiler().isEnabled())
		                    context.getProfiler().message(this, Profiler.OPTIMIZATION_FLAGS, "OPTIMIZATION FALLBACK", "Falling back to nodeSetCompare (" + xpe.getMessage() + ")");

		                if (LOG.isTraceEnabled())
		                	LOG.trace("Cannot convert key: " + Type.getTypeName(key.getType()) + " to required index type: " + Type.getTypeName(indexType));

			            return nodeSetCompare(nodes, contextSequence);
					}
		        }

		        // If key implements org.exist.storage.Indexable, we can use the index
		        if (key instanceof Indexable) {
		        	if (LOG.isTraceEnabled())
		        		LOG.trace("Checking if range index can be used for key: " + key.getStringValue());

		        	if (Type.subTypeOf(key.getType(), indexType)) {
			        	if(truncation == Constants.TRUNC_NONE) {
			        		if (LOG.isTraceEnabled())
			        			LOG.trace("Using range index for key: " + key.getStringValue());

			        		//key without truncation, find key
		                    context.getProfiler().message(this, Profiler.OPTIMIZATIONS, "OPTIMIZATION", "Using value index '" + context.getBroker().getValueIndex().toString() +
		                    		"' to find key '" + Type.getTypeName(key.getType()) + "(" + key.getStringValue() + ")'");

                            if (!checkForQNameIndex(contextSequence)) {
                                LOG.trace("Cannot use QName index");
                                contextQName = null;
                            }
                            
                            NodeSet ns = context.getBroker().getValueIndex().find(relation, docs, nodes, NodeSet.ANCESTOR, contextQName, (Indexable)key);
		                    hasUsedIndex = true;

		                    if (result == null)
								result = ns;
							else
								result = result.union(ns);

		                } else {
				        	//key with truncation, match key
                            if (LOG.isTraceEnabled())
                                context.getProfiler().message(this, Profiler.OPTIMIZATIONS, "OPTIMIZATION", "Using value index '" + context.getBroker().getValueIndex().toString() +
		                    		"' to match key '" + Type.getTypeName(key.getType()) + "(" + key.getStringValue() + ")'");

                            if (LOG.isTraceEnabled())
			        			LOG.trace("Using range index for key: " + key.getStringValue());

                            try {
								NodeSet ns = context.getBroker().getValueIndex().match(docs, nodes, NodeSet.ANCESTOR,
                                        getRegexp(key.getStringValue()).toString(), null, DBBroker.MATCH_REGEXP);
								hasUsedIndex = true;

								if (result == null)
									result = ns;
								else
									result = result.union(ns);

							} catch (EXistException e) {
								throw new XPathException(getASTNode(), e.getMessage(), e);
							}
						}
			        } else {
			        	//the datatype of our key does not
			        	//implement org.exist.storage.Indexable or is not of the correct type
		                if(context.getProfiler().isEnabled())
		                    context.getProfiler().message(this, Profiler.OPTIMIZATION_FLAGS, "OPTIMIZATION FALLBACK", "Falling back to nodeSetCompare (key is of type: " +
		                    		Type.getTypeName(key.getType()) + ") whereas index is of type '" + Type.getTypeName(indexType) + "'");

		                if (LOG.isTraceEnabled())
		                	LOG.trace("Cannot use range index: key is of type: " + Type.getTypeName(key.getType()) + ") whereas index is of type '" +
		                			Type.getTypeName(indexType));

		                return nodeSetCompare(nodes, contextSequence);
			        }		        	
		        } else {
		        	//our key does not implement org.exist.storage.Indexable